home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / spiele / publicdomain / elan / src / elan.c < prev    next >
C/C++ Source or Header  |  1996-06-07  |  73KB  |  2,613 lines

  1.  
  2. #include "global.h"
  3. #include "coredefs.h"
  4. #include "params.h"
  5. #include "texts.h"
  6. #include "symbols.h"
  7. #include "elan.h"
  8. #include "interf.h"
  9. #include "files.h"
  10.  
  11. environment env;
  12. systems sys;
  13. user usr;
  14.  
  15. int main(int argc, char *argv[])
  16.     {
  17.     event news;
  18.     cell *active_loc, *backup_loc;
  19.     user_command command;
  20.     channel *active_duct;
  21.     device_class dev_class;
  22.     mobile_class mob_class;
  23.     resource_type throughput_type;
  24.     int p, d;
  25.  
  26.     open_io();
  27.     srand((unsigned int)time(NULL));
  28.  
  29.     init_systems();
  30.     init_user();
  31.     init_environment();
  32.  
  33.     display_map();
  34.     display_message(place_habitat);
  35.  
  36.     news = no_news;
  37.     for(;;)
  38.         {
  39.         command = query_for_command(news);
  40.  
  41.         news = no_news;
  42.         switch(command.opcode)
  43.             {
  44.             case cmd_day:
  45.             news = next_day(TRUE);
  46.             break;
  47.  
  48.             case cmd_forward:
  49.             lock_interface();
  50.             do
  51.                 news = next_day(TRUE);
  52.             while(news == time_passed && !receive_interrupt());
  53.             unlock_interface();
  54.             break;
  55.  
  56.             case cmd_year:
  57.             news = next_year(FALSE);
  58.             break;
  59.  
  60.             case cmd_swap_chl:
  61.             swap_channels(command.loc_arg);
  62.             display_cell(command.loc_arg);
  63.             break;
  64.  
  65.             case cmd_add_dev:
  66.             if(has_around_plants(command.loc_arg))
  67.                 {
  68.                 display_message(neighbor_plant);
  69.                 break;
  70.                 }
  71.             display_message(select_item_to_install);
  72.             dev_class = query_for_item(device_name, device_icon, device_price,
  73.                         usr.device_storage, DEVICE_CLASS_NUMBER);
  74.             if(dev_class == DEVICE_CLASS_NUMBER)
  75.                 {
  76.                 display_message(blank_message);
  77.                 break;
  78.                 }
  79.             if(!usr.device_storage[dev_class])
  80.                 {
  81.                 display_message(item_not_available);
  82.                 break;
  83.                 }
  84.             if(install_device(dev_class, command.loc_arg))
  85.                 {
  86.                 usr.device_storage[dev_class]--;
  87.  
  88.                 display_neighbors(command.loc_arg);
  89.                 display_message(blank_message);
  90.                 news = next_day(TRUE);
  91.                 }
  92.             break;
  93.  
  94.             case cmd_del_dev:
  95.             remove_device(command.loc_arg->plant);
  96.             display_neighbors(command.loc_arg);
  97.             break;
  98.  
  99.             case cmd_del_chl:
  100.             active_duct = command.loc_arg->alfa_duct;
  101.  
  102.             active_loc = backup_loc = active_duct->start_loc;
  103.             while(active_loc)
  104.                 {
  105.                 if(active_loc->alfa_duct == active_duct)
  106.                     {
  107.                     backup_loc = active_loc->alfa_flow;
  108.  
  109.                     active_loc->alfa_duct = active_loc->beta_duct;
  110.                     active_loc->alfa_flow = active_loc->beta_flow;
  111.                     active_loc->beta_duct = NULL;
  112.                     active_loc->beta_flow = NULL;
  113.                     }
  114.                 else
  115.                     {
  116.                     backup_loc = active_loc->beta_flow;
  117.  
  118.                     active_loc->beta_duct = NULL;
  119.                     active_loc->beta_flow = NULL;
  120.                     }
  121.  
  122.                 active_loc->break_flow = NULL;
  123.                 active_loc->num_links = 0;
  124.  
  125.                 if(active_loc->alfa_duct)
  126.                     {
  127.                     set_icon(&active_loc->sym, CORNER_ICON);
  128.                     set_color(&active_loc->sym,
  129.                         resource_color[active_loc->alfa_duct->throughput_type]);
  130.                     }
  131.                 else
  132.                     clear_cell(active_loc);
  133.  
  134.                 display_cell(active_loc);
  135.  
  136.                 active_loc = backup_loc;
  137.                 }
  138.  
  139.             for(p = 0; p < sys.tot_plants; p++)
  140.                 {
  141.                 if(sys.plant[p]->input[active_duct->throughput_type] == active_duct)
  142.                     {
  143.                     sys.plant[p]->input[active_duct->throughput_type] = NULL;
  144.                     link_neighbors(sys.plant[p]->loc);
  145.                     display_neighbors(sys.plant[p]->loc);
  146.                     }
  147.                 }
  148.  
  149.             for(d = 0; d < sys.tot_ducts; d++)
  150.                 {
  151.                 if(sys.duct[d] == active_duct)
  152.                     {
  153.                     sys.tot_ducts--;
  154.                     sys.duct[d] = sys.duct[sys.tot_ducts];
  155.                     break;
  156.                     }
  157.                 }
  158.  
  159.             free(active_duct);
  160.             break;
  161.  
  162.             case cmd_add_mob:
  163.             if(!command.loc_arg->explored)
  164.                 {
  165.                 display_message(square_not_explored);
  166.                 break;
  167.                 }
  168.             display_message(select_item_to_install);
  169.             mob_class = query_for_item(mobile_name, mobile_icon, mobile_price,
  170.                                         usr.mobile_storage, PRIMARY_MC_NUMBER);
  171.             if(mob_class == PRIMARY_MC_NUMBER)
  172.                 {
  173.                 display_message(blank_message);
  174.                 break;
  175.                 }
  176.             if(!usr.mobile_storage[mob_class])
  177.                 {
  178.                 display_message(item_not_available);
  179.                 break;
  180.                 }
  181.             if(install_mobile(mob_class, command.loc_arg))
  182.                 {
  183.                 usr.mobile_storage[mob_class]--;
  184.  
  185.                 display_cell(command.loc_arg);
  186.                 display_message(blank_message);
  187.                 news = next_day(TRUE);
  188.                 }
  189.             break;
  190.  
  191.             case cmd_buy_dev:
  192.             purchase_items(device_name, device_icon, device_price,
  193.                             usr.device_storage, DEVICE_CLASS_NUMBER);
  194.             break;
  195.  
  196.             case cmd_buy_mob:
  197.             purchase_items(mobile_name, mobile_icon, mobile_price,
  198.                             usr.mobile_storage, PRIMARY_MC_NUMBER);
  199.             break;
  200.  
  201.             case cmd_trade_dev:
  202.             trade_resource(command.loc_arg->plant,
  203.                 command.loc_arg->plant->max_capacity * max(0, min(1, command.num_arg)));
  204.             display_cell(command.loc_arg);
  205.             display_user();
  206.             break;
  207.  
  208.             case cmd_switch_dev:
  209.             command.loc_arg->plant->demand_driven = !command.loc_arg->plant->demand_driven;
  210.             break;
  211.  
  212.             case cmd_set_dev:
  213.             if(!command.loc_arg->plant->demand_driven)
  214.                 command.loc_arg->plant->target_output =
  215.                     command.loc_arg->plant->max_state * max(0, min(1, command.num_arg));
  216.             break;
  217.  
  218.             case cmd_set_mob:
  219.             if(command.loc_arg->turtle->remote_control)
  220.                 upload_program(((int)floor(command.num_arg) + PRIMARY_PT_NUMBER) %
  221.                                 PRIMARY_PT_NUMBER, command.loc_arg->turtle);
  222.             break;
  223.  
  224.             case cmd_reset:
  225.             init_environment();
  226.             display_map();
  227.             display_message(place_habitat);
  228.             break;
  229.  
  230.             case cmd_start:
  231.             start_game(command.loc_arg);
  232.             news = shuttle_arrival;
  233.             break;
  234.  
  235.             case cmd_load:
  236.             load_game();
  237.             news = time_passed;
  238.             break;
  239.  
  240.             case cmd_save:
  241.             save_game();
  242.             break;
  243.  
  244.             case cmd_dump:
  245.             if(dump_map() != ok)
  246.                 display_message(save_error);
  247.             break;
  248.  
  249.             case cmd_quit:
  250.             end_game();
  251.             pause();
  252.             clean_exit(0);
  253.             break;
  254.  
  255.             case cmd_esc:
  256.             clean_exit(0);
  257.             break;
  258.  
  259.             case cmd_add_chl:
  260.             throughput_type = command.loc_arg->plant->output_type;
  261.             if(throughput_type >= PRIMARY_RT_NUMBER)
  262.                 {
  263.                 news = extension_failure;
  264.                 display_message(resource_not_exportable);
  265.                 break;
  266.                 }
  267.             if(channel_unit_price[throughput_type] > usr.money)
  268.                 {
  269.                 news = extension_failure;
  270.                 display_message(insuff_money_to_build_channel);
  271.                 break;
  272.                 }
  273.             active_duct = install_channel(command.loc_arg->plant, command.dir_arg);
  274.             if(!active_duct)
  275.                 {
  276.                 news = extension_failure;
  277.                 break;
  278.                 }
  279.             usr.money -= channel_unit_price[throughput_type];
  280.  
  281.             display_neighbors(active_duct->end_loc);
  282.             news = next_day(TRUE);
  283.             break;
  284.  
  285.             case cmd_ext_chl:
  286.             active_duct = command.loc_arg->alfa_duct;
  287.             throughput_type = active_duct->throughput_type;
  288.             if(channel_unit_price[throughput_type] > usr.money)
  289.                 {
  290.                 news = extension_failure;
  291.                 display_message(insuff_money_to_build_channel);
  292.                 break;
  293.                 }
  294.             if(!extend_channel(active_duct, command.loc_arg, command.dir_arg))
  295.                 {
  296.                 news = extension_failure;
  297.                 break;
  298.                 }
  299.             usr.money -= channel_unit_price[throughput_type];
  300.  
  301.             display_neighbors(active_duct->end_loc);
  302.             news = next_day(TRUE);
  303.             break;
  304.  
  305.             default:
  306.             assert(0);
  307.             break;
  308.             }
  309.         }
  310.     }
  311.  
  312. void clean_exit(int rv)
  313.     {
  314.     int p;
  315.  
  316.     for(p = 0; p < sys.tot_plants; p++)
  317.         free(sys.plant[p]);
  318.  
  319.     for(p = 0; p < sys.tot_ducts; p++)
  320.         free(sys.duct[p]);
  321.  
  322.     for(p = 0; p < sys.tot_turtles; p++)
  323.         free(sys.turtle[p]);
  324.  
  325.     close_io();
  326.  
  327.     exit(rv);
  328.     }
  329.  
  330. void purchase_items(const char **name, const icon_type *icon, const real *price,
  331.     int *storage, int class_number)
  332.     {
  333.     int class;
  334.  
  335.     display_message(select_item_to_buy);
  336.     for(;;)
  337.         {
  338.         class = query_for_item(name, icon, price, storage, class_number);
  339.  
  340.         if(class == class_number)
  341.             {
  342.             display_message(blank_message);
  343.             break;
  344.             }
  345.         if(price[class] > usr.money)
  346.             {
  347.             display_message(insuff_money_to_buy_item);
  348.             break;
  349.             }
  350.  
  351.         usr.money -= price[class];
  352.         storage[class]++;
  353.  
  354.         display_user();
  355.         }
  356.     }
  357.  
  358. void explore_neighbors(cell *loc)
  359.     {
  360.     cell *near_loc;
  361.     direction dir;
  362.  
  363.     for(dir = 0; dir < DIRECTION_NUMBER; dir++)
  364.         {
  365.         near_loc = neighbor(loc, dir);
  366.         if(!near_loc->explored)         /* Impianti e canali non vi rientrano */
  367.             {
  368.             near_loc->explored = TRUE;
  369.             if(near_loc->turtle)
  370.                 set_mobile_icon(near_loc->turtle);
  371.             else
  372.                 clear_cell(near_loc);
  373.             }
  374.         }
  375.     }
  376.  
  377. void link_neighbors(cell *loc)
  378.     {
  379.     cell *near_loc, *link_loc;
  380.     direction dir;
  381.  
  382.     for(dir = 0; dir < DIRECTION_NUMBER; dir++)
  383.         {
  384.         near_loc = neighbor(loc, dir);
  385.         link_loc = NULL;
  386.  
  387.         if(loc->plant)
  388.             {
  389.             if(near_loc->alfa_duct && !near_loc->beta_duct)
  390.                 {
  391.                 if(link_device(loc->plant, near_loc->alfa_duct))        /* Non mettere || */
  392.                     link_loc = near_loc;
  393.                 if(link_channel(near_loc->alfa_duct, loc->plant))
  394.                     link_loc = near_loc;
  395.                 }
  396.             }
  397.         else
  398.             if(loc->alfa_duct && !loc->beta_duct)
  399.                 {
  400.                 if(near_loc->plant)
  401.                     {
  402.                     if(link_device(near_loc->plant, loc->alfa_duct))        /* Non mettere || */
  403.                         link_loc = loc;
  404.                     if(link_channel(loc->alfa_duct, near_loc->plant))
  405.                         link_loc = loc;
  406.                     }
  407.                 }
  408.             else
  409.                 break;
  410.  
  411.         if(link_loc)
  412.             {
  413.             link_loc->num_links++;
  414.             set_icon(&link_loc->sym, LINK_ICON(link_loc->num_links));
  415.             }
  416.         }
  417.     }
  418.  
  419. real trade_resource(device *plant, real requested_capacity)
  420.     {
  421.     real traded_capacity;
  422.     real traded_money;
  423.  
  424.     assert(requested_capacity >= 0 && requested_capacity <= plant->max_capacity);
  425.  
  426.     if(plant->output_type >= PRIMARY_RT_NUMBER || plant->broken)
  427.         return 0;
  428.  
  429.     traded_capacity = requested_capacity - plant->current_capacity;
  430.     traded_money = resource_unit_price[plant->output_type] * traded_capacity;
  431.     if(usr.money >= traded_money)
  432.         {
  433.         usr.money -= traded_money;
  434.         plant->current_capacity += traded_capacity;
  435.         }
  436.     else
  437.         {
  438.         traded_capacity = usr.money / resource_unit_price[plant->output_type];
  439.         plant->current_capacity += traded_capacity;
  440.         usr.money = 0;
  441.         }
  442.  
  443.     update_device_icon(plant);
  444.  
  445.     return traded_capacity;
  446.     }
  447.  
  448. event next_day(boolean trace)
  449.     {
  450.     event news;
  451.  
  452.     update_systems(trace);
  453.  
  454.     if(usr.colony_dead)
  455.         news = time_passed;
  456.     else
  457.         {
  458.         if(usr.humans || usr.hybrids)
  459.             {
  460.             switch(env.time % BASE_PERIOD)
  461.                 {
  462.                 case 0:
  463.                 if(place_around_providers(1, space_shuttle, human_life_support))
  464.                     {
  465.                     usr.shuttle_landed = TRUE;
  466.                     news = shuttle_arrival;
  467.                     display_message(shuttle_arrived);
  468.                     }
  469.                 else
  470.                     news = time_passed;
  471.                 break;
  472.  
  473.                 case SHUTTLE_STAY:
  474.                 if(usr.shuttle_landed)
  475.                     {
  476.                     usr.shuttle_landed = FALSE;
  477.                     news = shuttle_departure;
  478.                     display_message(shuttle_departed);
  479.                     }
  480.                 else
  481.                     news = time_passed;
  482.                 break;
  483.  
  484.                 default:
  485.                 news = time_passed;
  486.                 break;
  487.                 }
  488.             }
  489.         else
  490.             {
  491.             usr.colony_dead = TRUE;
  492.             news = colony_end;
  493.             display_message(colony_terminated);
  494.             }
  495.         }
  496.  
  497.     if(trace)
  498.         display_frame();
  499.  
  500.     return news;
  501.     }
  502.  
  503. event next_year(boolean trace)
  504.     {
  505.     event news;
  506.  
  507.     lock_interface();
  508.     do
  509.         news = next_day(trace);
  510.     while(news == time_passed && env.time % BASE_PERIOD);
  511.     if(!trace)
  512.         {
  513.         display_map();
  514.         display_frame();
  515.         }
  516.     unlock_interface();
  517.  
  518.     return news;
  519.     }
  520.  
  521. void update_systems(boolean trace)
  522.     {
  523.     resource_type g;
  524.     channel *duct;
  525.     device *plant;
  526.     mobile *turtle;
  527.     int p, d, t;
  528.     cell *loc, *near_loc;
  529.     real gamma, delta;
  530.     int phi, psi;
  531.  
  532.     update_environment();
  533.     if(random(1) < GIZMO_FACTOR)
  534.         {
  535.         loc = &env.map[(int)floor(random(MAP_ROWS))][(int)floor(random(MAP_COLS))];
  536.         if(!loc->explored && !loc->turtle && random(1) < loc->ground_factor)
  537.             install_mobile(plasma_gizmo, loc);
  538.         }
  539.  
  540.     for(d = 0; d < sys.tot_ducts; d++)
  541.         {
  542.         duct = sys.duct[d];
  543.         duct->current_throughput = 0;
  544.         duct->target_throughput = 0;
  545.         duct->demanded_throughput = 0;
  546.  
  547.         loc = duct->break_loc;
  548.         if(loc &&
  549.             random(pow((real)(sys.tot_ducts * duct->length), 0.5)) <
  550.             random(usr.humans * REPAIR_FACTOR))
  551.             {
  552.             if(loc->break_flow == loc)
  553.                 {
  554.                 duct->break_loc = NULL;
  555.                 display_message(channel_repaired);
  556.                 }
  557.             else
  558.                 {
  559.                 loc = loc->break_flow;
  560.                 duct->break_loc->break_flow = loc->break_flow;
  561.                 }
  562.             loc->break_flow = NULL;
  563.  
  564.             set_attribute(&loc->sym, plain);
  565.             if(trace)
  566.                 display_cell(loc);
  567.             }
  568.         }
  569.  
  570.     sys.demand[human_life_support - SECONDARY_RT_BASE] += usr.humans + usr.human_growing;
  571.     sys.demand[hybrid_life_support - SECONDARY_RT_BASE] += usr.hybrids + usr.hybrid_growing +
  572.                                                         usr.pantropic_growing;
  573.     sys.demand[morphing_power - SECONDARY_RT_BASE] += usr.humans;
  574.     /* += in caso qualche mobile ne avesse fatto richiesta */
  575.  
  576.     for(g = 0; g < SECONDARY_RT_NUMBER; g++)
  577.         sys.offer[g] = 0;
  578.  
  579.     for(p = 0; p < sys.tot_plants; p++)
  580.         {
  581.         plant = sys.plant[p];
  582.         loc = plant->loc;
  583.  
  584.         if(plant->broken &&
  585.             random(sys.tot_plants) <
  586.             random(usr.humans * ((plant->output_type == human_life_support)?
  587.                                         CRITICAL_REPAIR_FACTOR : REPAIR_FACTOR)))
  588.             {
  589.             plant->broken = FALSE;
  590.             display_message(system_repaired);
  591.             }
  592.  
  593.         if(plant->output_type < PRIMARY_RT_NUMBER)
  594.             update_device(plant);
  595.         else
  596.             {
  597.             g = plant->output_type - SECONDARY_RT_BASE;
  598.  
  599.             if(sys.demand[g] <= plant->available_output)
  600.                 {
  601.                 plant->surplus_output -= sys.demand[g];
  602.                 sys.demand[g] = 0;
  603.                 }
  604.             else
  605.                 {
  606.                 sys.demand[g] -= plant->available_output;
  607.                 plant->surplus_output = -plant->max_state;  /* Tempo di salita minimo */
  608.                 }
  609.             plant->available_output = 0;        /* Risorsa secondaria non recuperabile */
  610.  
  611.             update_device(plant);
  612.  
  613.             sys.offer[g] += plant->available_output;
  614.             }
  615.  
  616.         if(trace)
  617.             display_cell(loc);
  618.         }
  619.  
  620.     for(g = 0; g < SECONDARY_RT_NUMBER; g++)
  621.         sys.demand[g] = 0;
  622.  
  623.     if(sys.sort_turtles)
  624.         {
  625.         sys.sort_turtles = FALSE;
  626.         qsort(sys.turtle, sys.tot_turtles, sizeof(*sys.turtle),
  627.                 (int (*)(const void *, const void *))mobile_priority);
  628.         while(!sys.turtle[sys.tot_turtles - 1])
  629.             sys.tot_turtles--;
  630.         }
  631.  
  632.     for(t = 0; t < sys.tot_turtles; t++)
  633.         {
  634.         turtle = sys.turtle[t];
  635.         loc = turtle->loc;
  636.  
  637.         if(turtle->time_to_remove)
  638.             {
  639.             turtle->time_to_remove--;
  640.             if(!turtle->time_to_remove)
  641.                 {
  642.                 remove_mobile(turtle);
  643.                 turtle = NULL;
  644.                 }
  645.             }
  646.  
  647.         if(turtle)
  648.             {
  649.             if(turtle->remote_control)
  650.                 {
  651.                 sys.demand[cpu_power - SECONDARY_RT_BASE]++;    /* Per il ciclo successivo */
  652.                 if(sys.offer[cpu_power - SECONDARY_RT_BASE] >= 1)
  653.                     {
  654.                     sys.offer[cpu_power - SECONDARY_RT_BASE]--;
  655.                     turtle->active = TRUE;
  656.                     }
  657.                 else
  658.                     turtle->active = FALSE;
  659.                 }
  660.  
  661.             near_loc = update_mobile(turtle);
  662.             if(trace && near_loc)
  663.                 display_cell(near_loc);     /* Può essere != turtle->loc */
  664.             }
  665.  
  666.         if(trace)
  667.             display_cell(loc);
  668.         }
  669.  
  670.     delta = delta_people(usr.humans + usr.human_growing,
  671.                         sys.offer[human_life_support - SECONDARY_RT_BASE]);
  672.     if(delta < 0)
  673.         {
  674.         if(usr.humans)
  675.             display_message(human_support_critical);
  676.  
  677.         usr.humans = floor(usr.humans + usr.human_growing + delta);
  678.         usr.human_growing = 0;
  679.         }
  680.     else
  681.         {
  682.         usr.human_growing += delta;
  683.         phi = floor(usr.human_growing);
  684.         if(phi)
  685.             {
  686.             usr.human_growing -= phi;
  687.             usr.humans += phi;
  688.  
  689.             display_message(human_birth);
  690.             }
  691.         }
  692.  
  693.     delta = delta_people(usr.hybrids + usr.pantropic_growing,
  694.                         sys.offer[hybrid_life_support - SECONDARY_RT_BASE]);
  695.     if(delta < 0)
  696.         {
  697.         if(usr.hybrids)
  698.             display_message(hybrid_support_critical);
  699.  
  700.         usr.hybrids = floor(usr.hybrids + usr.pantropic_growing + delta);
  701.         usr.pantropic_growing = 0;
  702.         }
  703.     else
  704.         {
  705.         usr.pantropic_growing += delta;
  706.         phi = floor(usr.pantropic_growing);
  707.         if(phi)
  708.             {
  709.             psi = MUTATION_RATIO * phi;
  710.             if(random(1) < MUTATION_RATIO)
  711.                 psi++;
  712.  
  713.             phi = place_around_providers(phi - psi, pantropic_form, hybrid_life_support);
  714.             psi = place_around_providers(psi, mutant_form, hybrid_life_support);
  715.  
  716.             if(phi || psi)
  717.                 {
  718.                 usr.pantropic_growing -= phi + psi;
  719.  
  720.                 if(phi >= psi)
  721.                     display_message(pantropic_birth);
  722.                 else
  723.                     display_message(mutant_birth);
  724.                 }
  725.             }
  726.         }
  727.  
  728.     usr.hybrid_growing = min(usr.humans,
  729.                             usr.hybrid_growing + sys.offer[morphing_power - SECONDARY_RT_BASE]);
  730.     phi = floor(usr.hybrid_growing);
  731.     if(phi)
  732.         {
  733.         gamma = max(0, sys.offer[hybrid_life_support - SECONDARY_RT_BASE] -
  734.                             (usr.hybrids + usr.pantropic_growing));
  735.         if(phi <= gamma)
  736.             {
  737.             usr.hybrid_growing -= phi;
  738.             usr.humans -= phi;
  739.             usr.hybrids += phi;
  740.  
  741.             display_message(hybrid_morphed);
  742.             }
  743.         else
  744.             if(usr.hybrid_growing > HYBRID_SUPPORT_MARGIN * gamma)
  745.                 usr.hybrid_growing = HYBRID_SUPPORT_MARGIN * gamma;
  746.         }
  747.  
  748.     usr.score = MONEY_VALUE * usr.money + HUMANS_VALUE * usr.humans +
  749.                 HYBRIDS_VALUE * usr.hybrids + PANTROPICS_VALUE * usr.pantropics;
  750.     }
  751.  
  752. real delta_people(real people, real life_support)
  753.     {
  754.     real delta;
  755.  
  756.     if(life_support)
  757.         {
  758.         delta = LIFE_KAPPA * people * (1 - people / life_support);
  759.         if(delta < 0)
  760.             delta = max(delta, -people);
  761.         else
  762.             {
  763.             if(people >= 2)
  764.                 delta *= BIRTH_RATIO;
  765.             else
  766.                 delta = 0;
  767.             }
  768.         }
  769.     else
  770.         delta = -people;
  771.  
  772.     delta = random(random(delta));
  773.  
  774.     return delta;
  775.     }
  776.  
  777. channel *init_channel(device *source_plant, int num, direction dir)
  778.     {
  779.     channel *duct;
  780.     cell *loc;
  781.  
  782.     assert(source_plant->output_type < PRIMARY_RT_NUMBER);
  783.  
  784.     loc = neighbor(source_plant->loc, dir);
  785.  
  786.     if(loc->plant || loc->alfa_duct || loc->turtle)
  787.         {
  788.         display_message(square_not_empty);
  789.         return NULL;    /* Si deve partire a livello 0 */
  790.         }
  791.  
  792.     duct = calloc(1, sizeof(*duct));
  793.     assert(duct != NULL);
  794.  
  795.     duct->throughput_type = source_plant->output_type;
  796.     duct->num = num;
  797.     duct->start_loc = duct->end_loc = loc;
  798.     duct->break_loc = NULL;
  799.     duct->length = 1;
  800.     duct->current_throughput = 0;
  801.     duct->target_throughput = 0;
  802.     duct->demanded_throughput = 0;
  803.  
  804.     loc->alfa_duct = duct;
  805.     loc->explored = TRUE;
  806.     set_icon(&loc->sym, channel_icon[dir]);
  807.     set_color(&loc->sym, resource_color[source_plant->output_type]);
  808.  
  809.     return duct;
  810.     }
  811.  
  812. channel *install_channel(device *source_plant, direction dir)
  813.     {
  814.     channel *duct;
  815.  
  816.     if(sys.tot_ducts == MAX_CHANNEL_NUMBER)
  817.         {
  818.         display_message(too_many_channels);
  819.         return NULL;
  820.         }
  821.  
  822.     duct = init_channel(source_plant, sys.num_ducts[source_plant->output_type], dir);
  823.     if(duct)
  824.         {
  825.         sys.duct[sys.tot_ducts] = duct;
  826.         sys.tot_ducts++;
  827.         sys.num_ducts[source_plant->output_type]++;
  828.  
  829.         explore_neighbors(duct->end_loc);
  830.         link_neighbors(duct->end_loc);
  831.         }
  832.  
  833.     return duct;
  834.     }
  835.  
  836. cell *extend_channel(channel *duct, cell *loc, direction dir)
  837.     {
  838.     cell *new_loc;
  839.  
  840.     new_loc = neighbor(loc, dir);
  841.  
  842.     if(new_loc->plant || new_loc->beta_duct || new_loc->turtle ||
  843.         new_loc->break_flow || new_loc->num_links || new_loc->alfa_duct == duct)
  844.         {
  845.         display_message(impossible_to_cross_square);
  846.         return NULL;
  847.         }
  848.  
  849.     if(duct->end_loc->alfa_duct == duct)
  850.         duct->end_loc->alfa_flow = new_loc;
  851.     else
  852.         duct->end_loc->beta_flow = new_loc;
  853.  
  854.     duct->end_loc = new_loc;
  855.     duct->length++;
  856.  
  857.     if(!new_loc->alfa_duct)
  858.         {
  859.         new_loc->alfa_duct = duct;
  860.         new_loc->explored = TRUE;
  861.  
  862.         set_icon(&new_loc->sym, channel_icon[dir]);
  863.         set_color(&new_loc->sym, resource_color[duct->throughput_type]);
  864.  
  865.         explore_neighbors(new_loc);
  866.         link_neighbors(new_loc);
  867.         }
  868.     else
  869.         {
  870.         new_loc->beta_duct = new_loc->alfa_duct;
  871.         new_loc->beta_flow = new_loc->alfa_flow;
  872.         new_loc->alfa_duct = duct;
  873.         new_loc->alfa_flow = NULL;
  874.  
  875.         set_icon(&new_loc->sym, CROSS_ICON);
  876.         set_color(&new_loc->sym, resource_color[duct->throughput_type]);
  877.         }
  878.  
  879.     if(loc->sym.icon != channel_icon[dir] && !loc->beta_duct && !loc->num_links)
  880.         set_icon(&loc->sym, CORNER_ICON);
  881.  
  882.     return new_loc;
  883.     }
  884.  
  885. void swap_channels(cell *loc)
  886.     {
  887.     channel *backup_duct;
  888.     cell *backup_loc;
  889.  
  890.     backup_duct = loc->beta_duct;
  891.     backup_loc = loc->beta_flow;
  892.     loc->beta_duct = loc->alfa_duct;
  893.     loc->beta_flow = loc->alfa_flow;
  894.     loc->alfa_duct = backup_duct;
  895.     loc->alfa_flow = backup_loc;
  896.  
  897.     set_color(&loc->sym, resource_color[backup_duct->throughput_type]);
  898.     }
  899.  
  900. boolean link_channel(channel *duct, device *plant)
  901.     {
  902.     int p;
  903.  
  904.     if(duct->throughput_type == plant->output_type)
  905.         {
  906.         for(p = 0; p < MAX_PROVIDERS_NUMBER; p++)
  907.             {
  908.             if(duct->provider[p] == plant)
  909.                 break;
  910.  
  911.             if(!duct->provider[p])
  912.                 {
  913.                 duct->provider[p] = plant;
  914.                 qsort(duct->provider, p + 1, sizeof(*duct->provider),
  915.                         (int (*)(const void *, const void *))device_priority);
  916.                 return TRUE;
  917.                 }
  918.             }
  919.         }
  920.     return FALSE;
  921.     }
  922.  
  923. int device_priority(const device **plant_1, const device **plant_2)
  924.     {
  925.     if(!*plant_1)
  926.         return (*plant_2)? 1 : 0;
  927.     else
  928.         if(!*plant_2)
  929.             return -1;
  930.         else
  931.             if((*plant_1)->id.class != (*plant_2)->id.class)
  932.                 return (*plant_1)->id.class - (*plant_2)->id.class;
  933.             else
  934.                 return (*plant_1)->id.num - (*plant_2)->id.num;
  935.     }
  936.  
  937. int mobile_priority(const mobile **turtle_1, const mobile **turtle_2)
  938.     {
  939.     if(!*turtle_1)
  940.         return (*turtle_2)? 1 : 0;
  941.     else
  942.         if(!*turtle_2)
  943.             return -1;
  944.         else
  945.             return (*turtle_1)->class - (*turtle_2)->class;
  946.     }
  947.  
  948. boolean link_device(device *plant, channel *duct)
  949.     {
  950.     if(plant->unit_consume[duct->throughput_type] && !plant->input[duct->throughput_type])
  951.         {
  952.         plant->input[duct->throughput_type] = duct;
  953.         return TRUE;
  954.         }
  955.     else
  956.         return FALSE;
  957.     }
  958.  
  959. void init_systems()
  960.     {
  961.     sys.tot_plants = 0;
  962.     sys.tot_ducts = 0;
  963.     sys.tot_turtles = 0;
  964.     sys.sort_turtles = FALSE;
  965.     }
  966.  
  967. void init_user()
  968.     {
  969.     device_class dev_class;
  970.     mobile_class mob_class;
  971.  
  972.     usr.money = INITIAL_MONEY;
  973.     usr.humans = HABITAT_DEFAULT_PEOPLE;
  974.     usr.hybrids = 0;
  975.     usr.pantropics = 0;
  976.     usr.human_growing = 0;
  977.     usr.hybrid_growing = 0;
  978.     usr.pantropic_growing = 0;
  979.     usr.robots = 0;
  980.     usr.hostiles = 0;
  981.     usr.score = 0;
  982.     for(dev_class = 0; dev_class < DEVICE_CLASS_NUMBER; dev_class++)
  983.         usr.device_storage[dev_class] = 0;
  984.     for(mob_class = 0; mob_class < PRIMARY_MC_NUMBER; mob_class++)
  985.         usr.device_storage[mob_class] = 0;
  986.     usr.shuttle_landed = TRUE;
  987.     usr.colony_dead = FALSE;
  988.     }
  989.  
  990. void init_environment()
  991.     {
  992.     int i, j, k;
  993.     cell *loc, *loc_2;
  994.  
  995.     for(i = 0; i < MAP_ROWS; i++)
  996.         for(j = 0; j < MAP_COLS; j++)
  997.             {
  998.             loc = &env.map[i][j];   /* Trama di base, necessaria per creare il ground */
  999.  
  1000.             loc->pos.i = i;
  1001.             loc->pos.j = j;
  1002.             loc->plant = NULL;
  1003.             loc->beta_duct = loc->alfa_duct = NULL;
  1004.             loc->beta_flow = loc->alfa_flow = NULL;
  1005.             loc->break_flow = NULL;
  1006.             loc->num_links = 0;
  1007.             loc->ground_factor = AVERAGE_GROUND_FACTOR;
  1008.             loc->explored = FALSE;
  1009.             }
  1010.  
  1011.     loc = &env.map[0][0];
  1012.     loc_2 = &env.map[MAP_ROWS / 2][MAP_COLS / 2];
  1013.     for(k = 0; k < GROUND_AREA; k++)
  1014.         {
  1015.         loc = neighbor(loc, (direction)floor(random(DIRECTION_NUMBER)));
  1016.         loc_2 = neighbor(loc_2, (direction)floor(random(DIRECTION_NUMBER)));
  1017.         loc->ground_factor = min(1, loc->ground_factor + DELTA_GROUND_FACTOR);
  1018.         loc_2->ground_factor = max(0, loc_2->ground_factor - DELTA_GROUND_FACTOR);
  1019.         }
  1020.  
  1021.     for(i = 0; i < MAP_ROWS; i++)
  1022.         for(j = 0; j < MAP_COLS; j++)
  1023.             clear_cell(&env.map[i][j]);
  1024.  
  1025.     env.time = 0;
  1026.     env.solar_factor = env.temperature_factor =
  1027.         env.air_factor = env.water_factor = env.growth_factor = 0.5;
  1028.     update_environment();
  1029.     env.time = 0;
  1030.     }
  1031.  
  1032. void clear_cell(cell *loc)
  1033.     {
  1034.     if(loc->explored)
  1035.         {
  1036.         set_icon(&loc->sym,
  1037.             explored_ground_icon[round(loc->ground_factor * (GROUND_ICON_NUMBER - 1))]);
  1038.         set_color(&loc->sym, explored_square_color);
  1039.         }
  1040.     else
  1041.         {
  1042.         set_icon(&loc->sym,
  1043.             unexplored_ground_icon[round(loc->ground_factor * (GROUND_ICON_NUMBER - 1))]);
  1044.         set_color(&loc->sym, unexplored_square_color);
  1045.         }
  1046.     set_attribute(&loc->sym, plain);
  1047.     }
  1048.  
  1049. cell *neighbor(cell *loc, direction dir)
  1050.     {
  1051.     position pos;
  1052.  
  1053.     pos = loc->pos;
  1054.  
  1055.     switch(dir)
  1056.         {
  1057.         case N:
  1058.         pos.i--;
  1059.         break;
  1060.  
  1061.         case S:
  1062.         pos.i++;
  1063.         break;
  1064.  
  1065.         case W:
  1066.         pos.j--;
  1067.         break;
  1068.  
  1069.         case E:
  1070.         pos.j++;
  1071.         break;
  1072.  
  1073.         case NW:
  1074.         pos.i--;
  1075.         pos.j--;
  1076.         break;
  1077.  
  1078.         case SW:
  1079.         pos.i++;
  1080.         pos.j--;
  1081.         break;
  1082.  
  1083.         case NE:
  1084.         pos.i--;
  1085.         pos.j++;
  1086.         break;
  1087.  
  1088.         case SE:
  1089.         pos.i++;
  1090.         pos.j++;
  1091.         break;
  1092.  
  1093.         default:
  1094.         assert(0);
  1095.         break;
  1096.         };
  1097.  
  1098.     if(pos.i < 0)
  1099.         pos.i = MAP_ROWS - 1;
  1100.     else
  1101.         {
  1102.         if(pos.i >= MAP_ROWS)
  1103.             pos.i = 0;
  1104.         }
  1105.  
  1106.     if(pos.j < 0)
  1107.         pos.j = MAP_COLS - 1;
  1108.     else
  1109.         {
  1110.         if(pos.j >= MAP_COLS)
  1111.             pos.j = 0;
  1112.         }
  1113.  
  1114.     return &env.map[pos.i][pos.j];
  1115.     }
  1116.  
  1117. device *init_device(device_id plant_id, cell *loc)
  1118.     {
  1119.     device *plant;
  1120.  
  1121.     plant = calloc(1, sizeof(*plant));
  1122.     assert(plant != NULL);
  1123.  
  1124.     plant->id = plant_id;
  1125.     plant->loc = loc;
  1126.     plant->demand_driven = TRUE;
  1127.     plant->zeta_f = zeta_1;
  1128.     plant->tau = 0;
  1129.     plant->broken = FALSE;
  1130.  
  1131.     /* Eta: 0.95 per gli impianti di trasformazione, 0.98 per quelli di stoccaggio */
  1132.     switch(plant_id.class)
  1133.         {
  1134.         case solar_cell:
  1135.         plant->output_type = electricity;
  1136.         plant->eta = 0.95;
  1137.         plant->max_state = 600;
  1138.         plant->kappa = 0.70;
  1139.         plant->zeta_f = zeta_solar;
  1140.         plant->sigma = 0.001;
  1141.         break;
  1142.  
  1143.         case nuclear_reactor:
  1144.         plant->output_type = electricity;
  1145.         plant->eta = 0.95;
  1146.         plant->max_state = 5000;
  1147.         plant->kappa = 0.50;
  1148.         plant->unit_consume[water] = 0.05;
  1149.         plant->sigma = 0.001;
  1150.         break;
  1151.  
  1152.         case battery:
  1153.         plant->output_type = electricity;
  1154.         plant->eta = 0.98;
  1155.         plant->max_state = 800;
  1156.         plant->kappa = 0.90;
  1157.         plant->max_capacity = 12000;
  1158.         plant->unit_consume[electricity] = 1;
  1159.         plant->sigma = 0.0002;
  1160.         break;
  1161.  
  1162.         case heating_system:
  1163.         plant->output_type = heat;
  1164.         plant->eta = 0.95;
  1165.         plant->max_state = 220;
  1166.         plant->kappa = 0.25;
  1167.         plant->unit_consume[electricity] = 2;
  1168.         plant->zeta_f = zeta_temperature;
  1169.         plant->sigma = 0.001;
  1170.         break;
  1171.  
  1172.         case water_processor:
  1173.         plant->output_type = water;
  1174.         plant->eta = 0.95;
  1175.         plant->max_state = 175;
  1176.         plant->kappa = 0.30;
  1177.         plant->unit_consume[electricity] = 3;
  1178.         plant->zeta_f = zeta_water;
  1179.         plant->sigma = 0.001;
  1180.         break;
  1181.  
  1182.         case water_tank:
  1183.         plant->output_type = water;
  1184.         plant->eta = 0.98;
  1185.         plant->max_state = 250;
  1186.         plant->kappa = 0.50;
  1187.         plant->max_capacity = 9000;
  1188.         plant->unit_consume[water] = 1;
  1189.         plant->sigma = 0.0002;
  1190.         break;
  1191.  
  1192.         case air_processor:
  1193.         plant->output_type = air;
  1194.         plant->eta = 0.95;
  1195.         plant->max_state = 90;
  1196.         plant->kappa = 0.40;
  1197.         plant->unit_consume[electricity] = 4;
  1198.         plant->zeta_f = zeta_air;
  1199.         plant->sigma = 0.001;
  1200.         break;
  1201.  
  1202.         case air_tank:
  1203.         plant->output_type = air;
  1204.         plant->eta = 0.98;
  1205.         plant->max_state = 150;
  1206.         plant->kappa = 0.60;
  1207.         plant->max_capacity = 7500;
  1208.         plant->unit_consume[air] = 1;
  1209.         plant->sigma = 0.0002;
  1210.         break;
  1211.  
  1212.         case greenhouse:
  1213.         plant->output_type = food;
  1214.         plant->eta = 0.95;
  1215.         plant->max_state = 75;
  1216.         plant->kappa = 0.10;
  1217.         plant->unit_consume[electricity] = 0.8;
  1218.         plant->unit_consume[heat] = 1.2;
  1219.         plant->unit_consume[water] = 1.3;
  1220.         plant->unit_consume[air] = 0.3;
  1221.         plant->sigma = 0.001;
  1222.         break;
  1223.  
  1224.         case food_storage:
  1225.         plant->output_type = food;
  1226.         plant->eta = 0.98;
  1227.         plant->max_state = 80;
  1228.         plant->kappa = 0.35;
  1229.         plant->max_capacity = 2500;
  1230.         plant->unit_consume[food] = 1;
  1231.         plant->sigma = 0.0002;
  1232.         break;
  1233.  
  1234.         case plantation:
  1235.         plant->output_type = biomass;
  1236.         plant->eta = 0.95;
  1237.         plant->max_state = 11;
  1238.         plant->kappa = 0.15;
  1239.         plant->zeta_f = zeta_growth;
  1240.         plant->sigma = 0.001;
  1241.         break;
  1242.  
  1243.         case biomass_silo:
  1244.         plant->output_type = biomass;
  1245.         plant->eta = 0.98;
  1246.         plant->max_state = 50;
  1247.         plant->kappa = 0.30;
  1248.         plant->max_capacity = 6000;
  1249.         plant->unit_consume[biomass] = 1;
  1250.         plant->sigma = 0.0002;
  1251.         break;
  1252.  
  1253.         case yeaster:
  1254.         plant->output_type = elan;
  1255.         plant->eta = 0.95;
  1256.         plant->max_state = 9;
  1257.         plant->kappa = 0.10;
  1258.         plant->zeta_f = zeta_growth;
  1259.         plant->sigma = 0;
  1260.         break;
  1261.  
  1262.         case distillery:
  1263.         plant->output_type = elan;
  1264.         plant->eta = 0.95;
  1265.         plant->max_state = 33;
  1266.         plant->kappa = 0.20;
  1267.         plant->unit_consume[electricity] = 5;
  1268.         plant->unit_consume[heat] = 3;
  1269.         plant->unit_consume[biomass] = 1;
  1270.         plant->sigma = 0.001;
  1271.         break;
  1272.  
  1273.         case elan_tank:
  1274.         plant->output_type = elan;
  1275.         plant->eta = 0.98;
  1276.         plant->max_state = 100;
  1277.         plant->kappa = 0.50;
  1278.         plant->max_capacity = 5000;
  1279.         plant->unit_consume[elan] = 1;
  1280.         plant->sigma = 0.0002;
  1281.         break;
  1282.  
  1283.         case computer:
  1284.         plant->output_type = cpu_power;
  1285.         plant->eta = 0.95;
  1286.         plant->max_state = 4;
  1287.         plant->kappa = 0.80;
  1288.         plant->unit_consume[electricity] = 1.5;
  1289.         plant->sigma = 0.0003;
  1290.         break;
  1291.  
  1292.         case habitat:
  1293.         plant->output_type = human_life_support;
  1294.         plant->eta = 0.95;
  1295.         plant->current_output = HABITAT_DEFAULT_PEOPLE;
  1296.         plant->max_state = HABITAT_MAX_PEOPLE;
  1297.         plant->kappa = 0.10;
  1298.         plant->max_capacity = plant->current_capacity = HABITAT_MAX_CAPACITY;
  1299.         plant->unit_consume[electricity] = 1;
  1300.         plant->unit_consume[heat] = 1;
  1301.         plant->unit_consume[water] = 1;
  1302.         plant->unit_consume[air] = 1;
  1303.         plant->unit_consume[food] = 1;
  1304.         plant->sigma = 0.0001;
  1305.         break;
  1306.  
  1307.         case hybridome:
  1308.         plant->output_type = hybrid_life_support;
  1309.         plant->eta = 0.95;
  1310.         plant->max_state = HYBRIDOME_MAX_PEOPLE;
  1311.         plant->kappa = 0.10;
  1312.         plant->max_capacity = HYBRIDOME_MAX_CAPACITY;
  1313.         plant->unit_consume[electricity] = 1;           /* Unica limitazione di durata */
  1314.         plant->unit_consume[elan] = 1;
  1315.         plant->sigma = 0;
  1316.         break;
  1317.  
  1318.         case metamorpher:
  1319.         plant->output_type = morphing_power;
  1320.         plant->eta = 0.95;
  1321.         plant->max_state = 1;
  1322.         plant->kappa = 0.10;
  1323.         plant->unit_consume[electricity] = 1;
  1324.         plant->unit_consume[heat] = 1;
  1325.         plant->unit_consume[air] = 1;
  1326.         plant->unit_consume[elan] = 3;
  1327.         plant->sigma = 0.001;
  1328.         break;
  1329.  
  1330.         case radiator:
  1331.         plant->output_type = BARRIER_RESOURCE;
  1332.         plant->eta = 0.95;
  1333.         plant->max_state = 3 / BARRIER_FACTOR;
  1334.         plant->kappa = 1;
  1335.         plant->unit_consume[BARRIER_RESOURCE] = 1;
  1336.         plant->sigma = 0.0003;
  1337.         break;
  1338.  
  1339.         default:
  1340.         assert(0);
  1341.         break;
  1342.         }
  1343.  
  1344.     plant->available_output = plant->surplus_output = plant->current_output;
  1345.     plant->current_state = plant->current_output / plant->eta;
  1346.  
  1347.     return plant;
  1348.     }
  1349.  
  1350. device *install_device(device_class class, cell *loc)
  1351.     {
  1352.     device *plant;
  1353.     device_id plant_id;
  1354.  
  1355.     if(sys.tot_plants == MAX_DEVICE_NUMBER)
  1356.         {
  1357.         display_message(too_many_devices);
  1358.         return NULL;
  1359.         }
  1360.  
  1361.     if(loc->plant || loc->alfa_duct || loc->turtle)
  1362.         {
  1363.         display_message(square_not_empty);
  1364.         return NULL;
  1365.         }
  1366.  
  1367.     plant_id.class = class;
  1368.     plant_id.num = sys.num_plants[class];
  1369.  
  1370.     plant = init_device(plant_id, loc);
  1371.     if(plant)
  1372.         {
  1373.         loc->plant = plant;
  1374.         loc->explored = TRUE;
  1375.  
  1376.         sys.plant[sys.tot_plants] = plant;
  1377.         sys.tot_plants++;
  1378.         sys.num_plants[class]++;
  1379.         qsort(sys.plant, sys.tot_plants, sizeof(*sys.plant),
  1380.                 (int (*)(const void *, const void *))device_priority);
  1381.  
  1382.         set_device_icon(plant);
  1383.  
  1384.         explore_neighbors(loc);
  1385.         link_neighbors(loc);
  1386.         }
  1387.  
  1388.     return plant;
  1389.     }
  1390.  
  1391. void remove_device(device *plant)
  1392.     {
  1393.     channel *duct;
  1394.     boolean linked_duct;
  1395.     int p, d;
  1396.     direction dir;
  1397.     cell *near_loc;
  1398.  
  1399.     plant->loc->plant = NULL;
  1400.     clear_cell(plant->loc);
  1401.  
  1402.     for(p = 0; p < sys.tot_plants; p++)
  1403.         {
  1404.         if(sys.plant[p] == plant)
  1405.             {
  1406.             sys.plant[p] = NULL;
  1407.             qsort(sys.plant, sys.tot_plants, sizeof(*sys.plant),
  1408.                     (int (*)(const void *, const void *))device_priority);
  1409.             sys.tot_plants--;
  1410.             break;
  1411.             }
  1412.         }
  1413.  
  1414.     for(d = 0; d < sys.tot_ducts; d++)
  1415.         {
  1416.         duct = sys.duct[d];
  1417.         linked_duct = FALSE;
  1418.  
  1419.         for(p = 0; p < MAX_PROVIDERS_NUMBER; p++)
  1420.             {
  1421.             if(!duct->provider[p])
  1422.                 break;
  1423.  
  1424.             if(duct->provider[p] == plant)
  1425.                 {
  1426.                 duct->provider[p] = NULL;   /* Niente break! */
  1427.                 linked_duct = TRUE;
  1428.                 }
  1429.             }
  1430.         if(linked_duct)
  1431.             qsort(duct->provider, p, sizeof(*duct->provider),
  1432.                     (int (*)(const void *, const void *))device_priority);
  1433.  
  1434.         if(linked_duct || duct == plant->input[duct->throughput_type])
  1435.             {
  1436.             for(dir = 0; dir < DIRECTION_NUMBER; dir++)
  1437.                 {
  1438.                 near_loc = neighbor(plant->loc, dir);
  1439.                 if(near_loc->alfa_duct == duct && near_loc->num_links)
  1440.                     {
  1441.                     near_loc->num_links--;
  1442.                     /*** Bug di difficile soluzione: la locazione aggiornata
  1443.                     potrebbe non essere quella giusta, in caso di impianti
  1444.                     vicini; il caso non si presenta di frequente ***/
  1445.  
  1446.                     if(near_loc->num_links)
  1447.                         set_icon(&near_loc->sym, LINK_ICON(near_loc->num_links));
  1448.                     else
  1449.                         set_icon(&near_loc->sym, CORNER_ICON);
  1450.  
  1451.                     break;
  1452.                     }
  1453.                 }
  1454.             }
  1455.         }
  1456.  
  1457.     free(plant);
  1458.     }
  1459.  
  1460. real eval_cell(program *mcp, cell *loc)
  1461.     {
  1462.     real hf;
  1463.  
  1464.     hf = mcp->ground_tropism * loc->ground_factor;
  1465.  
  1466.     if(!loc->explored)
  1467.         hf += mcp->unexplored_tropism;
  1468.  
  1469.     if(loc->plant)
  1470.         hf += mcp->device_tropism;
  1471.  
  1472.     if(loc->alfa_duct)
  1473.         hf += mcp->channel_tropism;
  1474.  
  1475.     if(loc->turtle)
  1476.         hf += mcp->mobile_tropism;
  1477.  
  1478.     return hf;
  1479.     }
  1480.  
  1481. cell *select_cell(program *mcp, cell *loc_1, cell *loc_2)
  1482.     {
  1483.     real hf_1, hf_2;
  1484.  
  1485.     hf_1 = eval_cell(mcp, loc_1);
  1486.     hf_2 = eval_cell(mcp, loc_2);
  1487.  
  1488.     if(hf_1 > hf_2)
  1489.         {
  1490.         if(mcp->selection_wits * exp(hf_2 - hf_1) < random(1))
  1491.             return loc_1;
  1492.         }
  1493.     else
  1494.         if(hf_1 < hf_2)
  1495.             {
  1496.             if(mcp->selection_wits * exp(hf_1 - hf_2) < random(1))
  1497.                 return loc_2;
  1498.             }
  1499.         else
  1500.             if(mcp->selection_wits < random(1))
  1501.                 return NULL;
  1502.  
  1503.     return (mcp->selection_bias < random(1))? loc_1 : loc_2;
  1504.     }
  1505.  
  1506. void upload_program(program_tag tag, mobile *turtle)
  1507.     {
  1508.     turtle->mcp.tag = tag;
  1509.  
  1510.     switch(tag)
  1511.         {
  1512.         case survey:
  1513.         turtle->mcp.selection_wits = 0;
  1514.         turtle->mcp.selection_bias = 0;
  1515.         turtle->mcp.ground_tropism = 0;
  1516.         turtle->mcp.unexplored_tropism = 0;
  1517.         turtle->mcp.device_tropism = 0;
  1518.         turtle->mcp.channel_tropism = 0;
  1519.         turtle->mcp.mobile_tropism = 1;
  1520.         break;
  1521.  
  1522.         case explore:
  1523.         turtle->mcp.selection_wits = 0.50;
  1524.         turtle->mcp.selection_bias = 0.50;
  1525.         turtle->mcp.ground_tropism = 0.1;
  1526.         turtle->mcp.unexplored_tropism = 1;
  1527.         turtle->mcp.device_tropism = -1;
  1528.         turtle->mcp.channel_tropism = -1;
  1529.         turtle->mcp.mobile_tropism = 0;
  1530.         break;
  1531.  
  1532.         case hunt:
  1533.         turtle->mcp.selection_wits = 0.25;
  1534.         turtle->mcp.selection_bias = 0.25;
  1535.         turtle->mcp.ground_tropism = 1;
  1536.         turtle->mcp.unexplored_tropism = 0;
  1537.         turtle->mcp.device_tropism = -1;
  1538.         turtle->mcp.channel_tropism = -1;
  1539.         turtle->mcp.mobile_tropism = 1;
  1540.         break;
  1541.  
  1542.         case patrol:
  1543.         turtle->mcp.selection_wits = 0.25;
  1544.         turtle->mcp.selection_bias = 0.25;
  1545.         turtle->mcp.ground_tropism = -1;
  1546.         turtle->mcp.unexplored_tropism = -1;
  1547.         turtle->mcp.device_tropism = -1;
  1548.         turtle->mcp.channel_tropism = 0;
  1549.         turtle->mcp.mobile_tropism = 1;
  1550.         break;
  1551.  
  1552.         case wander:
  1553.         turtle->mcp.selection_wits = 1;
  1554.         turtle->mcp.selection_bias = 1;
  1555.         turtle->mcp.ground_tropism = 0;
  1556.         turtle->mcp.unexplored_tropism = 0;
  1557.         turtle->mcp.device_tropism = 0;
  1558.         turtle->mcp.channel_tropism = 0;
  1559.         turtle->mcp.mobile_tropism = 0;
  1560.         break;
  1561.  
  1562.         case pantropic_cp:
  1563.         turtle->mcp.selection_wits = 0.75;
  1564.         turtle->mcp.selection_bias = 0.75;
  1565.         turtle->mcp.ground_tropism = 3;
  1566.         turtle->mcp.unexplored_tropism = 0;
  1567.         turtle->mcp.device_tropism = 0;
  1568.         turtle->mcp.channel_tropism = 0;
  1569.         turtle->mcp.mobile_tropism = 0;
  1570.         break;
  1571.  
  1572.         case mutant_cp:
  1573.         turtle->mcp.selection_wits = 1;
  1574.         turtle->mcp.selection_bias = 1;
  1575.         turtle->mcp.ground_tropism = 0;
  1576.         turtle->mcp.unexplored_tropism = 0;
  1577.         turtle->mcp.device_tropism = 0;
  1578.         turtle->mcp.channel_tropism = 0;
  1579.         turtle->mcp.mobile_tropism = 0;
  1580.         break;
  1581.  
  1582.         case parasite_cp:
  1583.         turtle->mcp.selection_wits = 0.75;
  1584.         turtle->mcp.selection_bias = 0.75;
  1585.         turtle->mcp.ground_tropism = 3;
  1586.         turtle->mcp.unexplored_tropism = 0;
  1587.         turtle->mcp.device_tropism = 0;
  1588.         turtle->mcp.channel_tropism = 0;
  1589.         turtle->mcp.mobile_tropism = 0;
  1590.         break;
  1591.  
  1592.         case breeder_cp:
  1593.         turtle->mcp.selection_wits = 0.75;
  1594.         turtle->mcp.selection_bias = 0.75;
  1595.         turtle->mcp.ground_tropism = 3;
  1596.         turtle->mcp.unexplored_tropism = 1;
  1597.         turtle->mcp.device_tropism = 0;
  1598.         turtle->mcp.channel_tropism = 0;
  1599.         turtle->mcp.mobile_tropism = 0;
  1600.         break;
  1601.  
  1602.         case gizmo_cp:
  1603.         turtle->mcp.selection_wits = 1;
  1604.         turtle->mcp.selection_bias = 0.33;
  1605.         turtle->mcp.ground_tropism = 0;
  1606.         turtle->mcp.unexplored_tropism = 0;
  1607.         turtle->mcp.device_tropism = 0;
  1608.         turtle->mcp.channel_tropism = 0;
  1609.         turtle->mcp.mobile_tropism = 0;
  1610.         break;
  1611.  
  1612.         case mole_cp:
  1613.         turtle->mcp.selection_wits = 0.75;
  1614.         turtle->mcp.selection_bias = 0.75;
  1615.         turtle->mcp.ground_tropism = -3;
  1616.         turtle->mcp.unexplored_tropism = 0;
  1617.         turtle->mcp.device_tropism = 0;
  1618.         turtle->mcp.channel_tropism = 0;
  1619.         turtle->mcp.mobile_tropism = -1;
  1620.         break;
  1621.  
  1622.         default:
  1623.         assert(0);
  1624.         break;
  1625.         }
  1626.     }
  1627.  
  1628. cell *update_mobile(mobile *turtle)
  1629.     {
  1630.     cell *loc, *near_loc, *cmp_loc;
  1631.     direction dir;
  1632.     channel *duct;
  1633.  
  1634.     loc = turtle->loc;
  1635.  
  1636.     if(!turtle->active)
  1637.         near_loc = NULL;
  1638.     else
  1639.         {
  1640.         dir = floor(random(DIRECTION_NUMBER));
  1641.         near_loc = neighbor(loc, turtle->heading);
  1642.         cmp_loc = neighbor(loc, dir);
  1643.  
  1644.         near_loc = select_cell(&turtle->mcp, near_loc, cmp_loc);
  1645.         if(!near_loc)
  1646.             turtle->heading = floor(random(DIRECTION_NUMBER));
  1647.         else
  1648.             {
  1649.             if(near_loc == cmp_loc)
  1650.                 turtle->heading = dir;
  1651.  
  1652.             if(near_loc->plant)
  1653.                 {
  1654.                 switch(turtle->device_reaction)
  1655.                     {
  1656.                     case bump:
  1657.                     turtle->heading = floor(random(DIRECTION_NUMBER));
  1658.                     near_loc = NULL;
  1659.                     break;
  1660.  
  1661.                     case attack:
  1662.                     attack_device(near_loc->plant);
  1663.                     break;
  1664.  
  1665.                     case jump:
  1666.                     near_loc = jump_obstacle(turtle);
  1667.                     break;
  1668.  
  1669.                     default:
  1670.                     near_loc = NULL;
  1671.                     break;
  1672.                     }
  1673.                 }
  1674.             else
  1675.                 if(near_loc->alfa_duct)
  1676.                     {
  1677.                     if(near_loc->break_flow)
  1678.                         near_loc = jump_obstacle(turtle);
  1679.                     else
  1680.                         {
  1681.                         duct = near_loc->alfa_duct;
  1682.                         switch(turtle->channel_reaction)
  1683.                             {
  1684.                             case bump:
  1685.                             turtle->heading = floor(random(DIRECTION_NUMBER));
  1686.                             near_loc = NULL;
  1687.                             break;
  1688.  
  1689.                             case attack:
  1690.                             if(duct->throughput_type != BARRIER_RESOURCE ||
  1691.                                 random(1) < exp(-BARRIER_FACTOR * duct->current_throughput))
  1692.                                 attack_channel(duct, near_loc);
  1693.                             else
  1694.                                 {
  1695.                                 turtle->heading = floor(random(DIRECTION_NUMBER));
  1696.                                 near_loc = NULL;
  1697.                                 }
  1698.                             break;
  1699.  
  1700.                             case jump:
  1701.                             near_loc = jump_obstacle(turtle);
  1702.                             break;
  1703.  
  1704.                             default:
  1705.                             near_loc = NULL;
  1706.                             break;
  1707.                             }
  1708.                         }
  1709.                     }
  1710.                 else
  1711.                     if(near_loc->turtle)
  1712.                         {
  1713.                         switch(turtle->mobile_reaction[near_loc->turtle->class])
  1714.                             {
  1715.                             case bump:
  1716.                             turtle->heading = floor(random(DIRECTION_NUMBER));
  1717.                             near_loc = NULL;
  1718.                             break;
  1719.  
  1720.                             case attack:
  1721.                             attack_mobile(turtle, near_loc->turtle);
  1722.                             break;
  1723.  
  1724.                             case mate:
  1725.                             mate_mobile(turtle, near_loc->turtle);
  1726.                             break;
  1727.  
  1728.                             case jump:
  1729.                             near_loc = jump_obstacle(turtle);
  1730.                             break;
  1731.  
  1732.                             default:
  1733.                             near_loc = NULL;
  1734.                             break;
  1735.                             }
  1736.                         }
  1737.                     else
  1738.                         move_mobile(turtle, near_loc);
  1739.             }
  1740.         }
  1741.  
  1742.     if(loc == turtle->loc)              /* Non ci sono stati spostamenti */
  1743.         update_mobile_icon(turtle);
  1744.  
  1745.     return near_loc;
  1746.     }
  1747.  
  1748. void attack_device(device *plant)
  1749.     {
  1750.     damage_device(plant);
  1751.     update_device_icon(plant);
  1752.     display_message(system_attacked);
  1753.     }
  1754.  
  1755. void attack_channel(channel *duct, cell *loc)
  1756.     {
  1757.     if(!loc->beta_duct && !loc->break_flow && !loc->num_links)
  1758.         {
  1759.         if(!duct->break_loc)
  1760.             loc->break_flow = loc;
  1761.         else
  1762.             {
  1763.             loc->break_flow = duct->break_loc->break_flow;
  1764.             duct->break_loc->break_flow = loc;
  1765.             }
  1766.         duct->break_loc = loc;
  1767.         duct->current_throughput = 0;
  1768.  
  1769.         set_attribute(&loc->sym, broken_channel);
  1770.         display_message(channel_attacked);
  1771.         }
  1772.     }
  1773.  
  1774. mobile *init_mobile(mobile_class class, cell *loc)
  1775.     {
  1776.     mobile *turtle;
  1777.     mobile_class def_class;
  1778.  
  1779.     turtle = calloc(1, sizeof(*turtle));
  1780.     assert(turtle != NULL);
  1781.  
  1782.     turtle->class = class;
  1783.     turtle->loc = loc;
  1784.     turtle->heading = floor(random(DIRECTION_NUMBER));
  1785.     turtle->eta = 1;
  1786.  
  1787.     if(mobile_max_age[class] <= MIN_TIME_GRANTED)
  1788.         turtle->time_to_remove = mobile_max_age[class];
  1789.     else
  1790.         turtle->time_to_remove = MIN_TIME_GRANTED +
  1791.                                     floor(random(mobile_max_age[class] - MIN_TIME_GRANTED));
  1792.  
  1793.     for(def_class = 0; def_class < MOBILE_CLASS_NUMBER; def_class++)
  1794.         if(csi[class][def_class])
  1795.             turtle->mobile_reaction[def_class] = attack;
  1796.         else
  1797.             turtle->mobile_reaction[def_class] = bump;
  1798.  
  1799.     switch(class)
  1800.         {
  1801.         case roboprobe:
  1802.         turtle->active = TRUE;
  1803.         upload_program(explore, turtle);
  1804.         turtle->device_reaction = bump;
  1805.         turtle->channel_reaction = bump;
  1806.         turtle->explore_cell = TRUE;
  1807.         break;
  1808.  
  1809.         case raider:
  1810.         turtle->remote_control = TRUE;
  1811.         upload_program(survey, turtle);
  1812.         turtle->device_reaction = bump;
  1813.         turtle->channel_reaction = bump;
  1814.         turtle->explore_cell = TRUE;
  1815.         break;
  1816.  
  1817.         case exterminator:
  1818.         turtle->remote_control = TRUE;
  1819.         upload_program(survey, turtle);
  1820.         turtle->device_reaction = bump;
  1821.         turtle->channel_reaction = bump;
  1822.         turtle->explore_cell = TRUE;
  1823.         break;
  1824.  
  1825.         case stalker:
  1826.         turtle->remote_control = TRUE;
  1827.         upload_program(survey, turtle);
  1828.         turtle->device_reaction = bump;
  1829.         turtle->channel_reaction = jump;
  1830.         turtle->explore_cell = TRUE;
  1831.         break;
  1832.  
  1833.         case guardian:
  1834.         turtle->active = TRUE;
  1835.         upload_program(patrol, turtle);
  1836.         turtle->device_reaction = bump;
  1837.         turtle->channel_reaction = jump;
  1838.         turtle->explore_cell = TRUE;
  1839.         break;
  1840.  
  1841.         case pantropic_form:
  1842.         turtle->active = TRUE;
  1843.         upload_program(pantropic_cp, turtle);
  1844.         turtle->device_reaction = bump;
  1845.         turtle->channel_reaction = bump;
  1846.         turtle->can_breed = (random(1) < 0.5);
  1847.         if(!turtle->can_breed)
  1848.             turtle->mobile_reaction[pantropic_form] = mate;
  1849.         break;
  1850.  
  1851.         case mutant_form:
  1852.         turtle->active = TRUE;
  1853.         upload_program(mutant_cp, turtle);
  1854.         turtle->device_reaction = attack;
  1855.         turtle->channel_reaction = attack;
  1856.         break;
  1857.  
  1858.         case alien_parasite:
  1859.         turtle->active = TRUE;
  1860.         upload_program(parasite_cp, turtle);
  1861.         turtle->device_reaction = attack;
  1862.         turtle->channel_reaction = bump;
  1863.         turtle->mobile_reaction[alien_breeder] = mate;
  1864.         break;
  1865.  
  1866.         case alien_breeder:
  1867.         turtle->active = TRUE;
  1868.         upload_program(breeder_cp, turtle);
  1869.         turtle->device_reaction = attack;
  1870.         turtle->channel_reaction = attack;
  1871.         turtle->can_breed = TRUE;
  1872.         break;
  1873.  
  1874.         case plasma_gizmo:
  1875.         turtle->active = TRUE;
  1876.         upload_program(gizmo_cp, turtle);
  1877.         turtle->device_reaction = bump;
  1878.         turtle->channel_reaction = attack;
  1879.         turtle->can_breed = TRUE;
  1880.         turtle->steps_to_breed = turtle->time_to_remove / 3;
  1881.         break;
  1882.  
  1883.         case alien_mole:
  1884.         turtle->active = TRUE;
  1885.         upload_program(mole_cp, turtle);
  1886.         turtle->device_reaction = attack;
  1887.         turtle->channel_reaction = jump;
  1888.         break;
  1889.  
  1890.         case space_shuttle:
  1891.         turtle->active = TRUE;
  1892.         upload_program(survey, turtle);
  1893.         break;
  1894.  
  1895.         default:
  1896.         assert(0);
  1897.         break;
  1898.         }
  1899.  
  1900.     return turtle;
  1901.     }
  1902.  
  1903. mobile *install_mobile(mobile_class class, cell *loc)
  1904.     {
  1905.     mobile *turtle;
  1906.  
  1907.     if(sys.tot_turtles == MAX_MOBILE_NUMBER)
  1908.         {
  1909.         display_message(too_many_mobiles);
  1910.         return NULL;
  1911.         }
  1912.  
  1913.     if(loc->plant || loc->alfa_duct || loc->turtle)
  1914.         {
  1915.         display_message(square_not_empty);
  1916.         return NULL;
  1917.         }
  1918.  
  1919.     turtle = init_mobile(class, loc);
  1920.     if(turtle)
  1921.         {
  1922.         loc->turtle = turtle;
  1923.         if(turtle->explore_cell)
  1924.             loc->explored = TRUE;
  1925.  
  1926.         set_mobile_icon(turtle);
  1927.  
  1928.         sys.turtle[sys.tot_turtles] = turtle;
  1929.         sys.tot_turtles++;
  1930.         sys.sort_turtles = TRUE;
  1931.  
  1932.         if(turtle->class < PRIMARY_MC_NUMBER)
  1933.             usr.robots++;
  1934.         else
  1935.             switch(turtle->class)
  1936.                 {
  1937.                 case pantropic_form:
  1938.                 usr.pantropics++;
  1939.                 break;
  1940.  
  1941.                 case mutant_form:
  1942.                 case alien_parasite:
  1943.                 case alien_breeder:
  1944.                 case plasma_gizmo:
  1945.                 case alien_mole:
  1946.                 usr.hostiles++;
  1947.                 break;
  1948.  
  1949.                 case space_shuttle:
  1950.                 break;
  1951.  
  1952.                 default:
  1953.                 assert(0);
  1954.                 break;
  1955.                 }
  1956.         }
  1957.     return turtle;
  1958.     }
  1959.  
  1960. void remove_mobile(mobile *turtle)
  1961.     {
  1962.     int t;
  1963.  
  1964.     turtle->loc->turtle = NULL;
  1965.     clear_cell(turtle->loc);
  1966.  
  1967.     for(t = 0; t < sys.tot_turtles; t++)
  1968.         {
  1969.         if(sys.turtle[t] == turtle)
  1970.             {
  1971.             sys.turtle[t] = NULL;
  1972.             sys.sort_turtles = TRUE;    /* tot_turtles viene decrementato dopo il sort */
  1973.             break;
  1974.             }
  1975.         }
  1976.  
  1977.     if(turtle->class < PRIMARY_MC_NUMBER)
  1978.         usr.robots--;
  1979.     else
  1980.         switch(turtle->class)
  1981.             {
  1982.             case pantropic_form:
  1983.             usr.pantropics--;
  1984.             break;
  1985.  
  1986.             case mutant_form:
  1987.             case alien_parasite:
  1988.             case alien_breeder:
  1989.             case plasma_gizmo:
  1990.             case alien_mole:
  1991.             usr.hostiles--;
  1992.             break;
  1993.  
  1994.             case space_shuttle:
  1995.             break;
  1996.  
  1997.             default:
  1998.             assert(0);
  1999.             break;
  2000.             }
  2001.  
  2002.     free(turtle);
  2003.     }
  2004.  
  2005. real update_device(device *plant)
  2006.     {
  2007.     real actual_input, available_input, requested_input;
  2008.     real storage_output;
  2009.     real target_state, delta_state, next_state;
  2010.     real zeta;
  2011.  
  2012.     if(!plant->broken)
  2013.         {
  2014.         assert(plant->surplus_output <= plant->available_output ||
  2015.                 plant->output_type > PRIMARY_RT_NUMBER);
  2016.  
  2017.         /* Si recupera il recuperabile */
  2018.  
  2019.         plant->current_capacity = min(plant->max_capacity,
  2020.                                 plant->current_capacity + plant->available_output / plant->eta);
  2021.  
  2022.         /* Si decide un nuovo obiettivo */
  2023.  
  2024.         if(plant->demand_driven)
  2025.             plant->target_output = max(0, min(plant->max_state,
  2026.                                                 plant->current_output - plant->surplus_output));
  2027.         /* Si calcola il nuovo stato */
  2028.  
  2029.         target_state = min(plant->max_state, plant->target_output / plant->eta);
  2030.         delta_state = plant->kappa * (target_state - plant->current_state);
  2031.         next_state = max(0, plant->current_state + delta_state);
  2032.  
  2033.         requested_input = next_state + plant->max_capacity - plant->current_capacity;
  2034.         zeta = calc_zeta(plant->zeta_f, plant->loc);
  2035.         if(zeta)
  2036.             requested_input /= zeta;
  2037.         else
  2038.             requested_input = 0;    /* Si rinuncia */
  2039.  
  2040.         requested_input = min(plant->max_state, requested_input);
  2041.         available_input = poll_providers(plant, requested_input, demand);
  2042.         assert(available_input <= requested_input);
  2043.  
  2044.         /* E` sempre garantito che actual_input <= available_input <= requested_input */
  2045.         actual_input = zeta * available_input;
  2046.         storage_output = next_state - actual_input;
  2047.  
  2048.         if(storage_output <= plant->current_capacity)   /* Sistema libero */
  2049.             {
  2050.             plant->current_state = next_state;
  2051.             plant->current_capacity =
  2052.                 min(plant->max_capacity, plant->current_capacity - storage_output);
  2053.             /* Per ragioni numeriche, quando actual_input = requested_input e zeta < 1,
  2054.                 current_capacity poteva essere un eps > 0 anche se max_capacity = 0; fixed */
  2055.             }
  2056.         else
  2057.             {                                           /* Sistema vincolato */
  2058.             target_state = actual_input + plant->current_capacity;
  2059.             delta_state = plant->kappa * (target_state - plant->current_state);
  2060.             next_state = max(0, plant->current_state + delta_state);
  2061.  
  2062.             storage_output = next_state - actual_input;
  2063.  
  2064.             plant->current_state = next_state;
  2065.             plant->current_capacity = min(plant->max_capacity,
  2066.                 max(0, plant->current_capacity - storage_output));
  2067.             }
  2068.  
  2069.         poll_providers(plant, available_input, commit);
  2070.  
  2071.         plant->tau = min(1, plant->tau +
  2072.         (plant->sigma * (abs(delta_state) + RHO * plant->current_state) / plant->max_state));
  2073.  
  2074.         if(random(1) < plant->tau)
  2075.             {
  2076.             damage_device(plant);
  2077.             display_message(system_failure);
  2078.             }
  2079.         else
  2080.             {
  2081.             plant->current_output = plant->eta * plant->current_state;
  2082.             plant->available_output = plant->surplus_output = plant->current_output;
  2083.             }
  2084.  
  2085.         update_device_icon(plant);
  2086.         }
  2087.  
  2088.     return plant->current_output;
  2089.     }
  2090.  
  2091. void damage_device(device *plant)
  2092.     {
  2093.     plant->broken = TRUE;
  2094.     plant->current_state = 0;
  2095.     plant->current_capacity -= random(random(plant->current_capacity));
  2096.     plant->eta *= 1 - random(plant->tau);
  2097.     plant->tau = random(plant->tau);
  2098.  
  2099.     plant->available_output = plant->surplus_output = plant->current_output = 0;
  2100.     }
  2101.  
  2102. real poll_providers(device *plant, real request, request_mode mode)
  2103.     {
  2104.     resource_type g, c, num_constraints;
  2105.     channel *duct, *constraint[PRIMARY_RT_NUMBER];
  2106.     real consume, consume_to_go, deficit[PRIMARY_RT_NUMBER], ratio, new_ratio;
  2107.     device *provider;
  2108.     int p;
  2109.  
  2110.     ratio = 1;
  2111.     num_constraints = 0;
  2112.     if(request)
  2113.         {
  2114.         for(g = 0; g < PRIMARY_RT_NUMBER; g++)
  2115.             {
  2116.             consume = plant->unit_consume[g] * request;
  2117.             if(consume)
  2118.                 {
  2119.                 duct = plant->input[g];
  2120.                 if(!duct || duct->break_loc)
  2121.                     {
  2122.                     ratio = 0;
  2123.                     num_constraints = 0;
  2124.                     break;
  2125.                     }
  2126.  
  2127.                 consume_to_go = consume;
  2128.                 for(p = 0; p < MAX_PROVIDERS_NUMBER && consume_to_go > 0; p++)
  2129.                     {
  2130.                     provider = duct->provider[p];
  2131.                     if(!provider)
  2132.                         break;
  2133.  
  2134.                     if(plant->output_type != g || duct != provider->input[g])
  2135.                         {
  2136.                         switch(mode)
  2137.                             {
  2138.                             case demand:
  2139.                             if(consume_to_go <= provider->surplus_output)
  2140.                                 {
  2141.                                 provider->surplus_output -= consume_to_go;
  2142.                                 consume_to_go = 0;
  2143.                                 }
  2144.                             else
  2145.                                 {
  2146.                                 if(consume_to_go <= provider->available_output)
  2147.                                     consume_to_go = 0;
  2148.                                 else
  2149.                                     consume_to_go -= provider->available_output;
  2150.  
  2151.                                 if(provider->surplus_output > 0)
  2152.                                     provider->surplus_output = 0;
  2153.                                 }
  2154.                             break;
  2155.  
  2156.                             case commit:
  2157.                             if(consume_to_go <= provider->available_output)
  2158.                                 {
  2159.                                 provider->available_output -= consume_to_go;
  2160.                                 consume_to_go = 0;
  2161.                                 }
  2162.                             else
  2163.                                 {
  2164.                                 consume_to_go -= provider->available_output;
  2165.                                 provider->available_output = 0;
  2166.                                 }
  2167.                             break;
  2168.  
  2169.                             default:
  2170.                             assert(0);
  2171.                             break;
  2172.                             }
  2173.                         }
  2174.                     }
  2175.  
  2176.                 switch(mode)
  2177.                     {
  2178.                     case demand:
  2179.                     duct->target_throughput += consume;
  2180.                     if(consume_to_go)
  2181.                         {
  2182.                         new_ratio = 1 - consume_to_go / consume;
  2183.                         if(new_ratio < ratio + CONTROL_TOLL)
  2184.                             {
  2185.                             if(new_ratio < ratio)
  2186.                                 {
  2187.                                 if(new_ratio < ratio - CONTROL_TOLL)
  2188.                                     num_constraints = 0;
  2189.                                 ratio = new_ratio;
  2190.                                 }
  2191.                             constraint[num_constraints] = duct;
  2192.                             deficit[num_constraints] = consume_to_go;
  2193.                             num_constraints++;
  2194.                             }
  2195.                         }
  2196.                     break;
  2197.  
  2198.                     case commit:
  2199.                     duct->current_throughput += consume - consume_to_go;
  2200.                     if(consume_to_go)
  2201.                         {
  2202.                         new_ratio = 1 - consume_to_go / consume;
  2203.                         if(new_ratio < ratio)
  2204.                             ratio = new_ratio;
  2205.                         }
  2206.                     break;
  2207.  
  2208.                     default:
  2209.                     assert(0);
  2210.                     break;
  2211.                     }
  2212.                 }
  2213.             }
  2214.  
  2215.         if(mode == demand)
  2216.             {
  2217.             for(c = 0; c < num_constraints; c++)
  2218.                 {
  2219.                 g = constraint[c]->throughput_type;
  2220.                 constraint[c]->demanded_throughput += deficit[c];
  2221.  
  2222.                 for(p = 0; p < MAX_PROVIDERS_NUMBER; p++)
  2223.                     {
  2224.                     provider = constraint[c]->provider[p];
  2225.                     if(!provider)
  2226.                         break;
  2227.  
  2228.                     if(plant->output_type != g || constraint[c] != provider->input[g])
  2229.                         {
  2230.                         assert(provider->surplus_output <= 0);
  2231.                         provider->surplus_output -= deficit[c];
  2232.                         }
  2233.                     }
  2234.                 }
  2235.             }
  2236.         }
  2237.  
  2238.     return (real)(ratio * request);
  2239.     }
  2240.  
  2241. void set_device_icon(device *plant)
  2242.     {
  2243.     set_icon(&plant->loc->sym, device_icon[plant->id.class]);
  2244.     set_color(&plant->loc->sym, resource_color[plant->output_type]);
  2245.     update_device_icon(plant);
  2246.     }
  2247.  
  2248. void update_device_icon(device *plant)
  2249.     {
  2250.     if(plant->broken)
  2251.         set_attribute(&plant->loc->sym, broken_device);
  2252.     else
  2253.         if(plant->max_capacity)
  2254.             {
  2255.             if(plant->current_capacity > USER_EPS * plant->max_capacity)
  2256.                 set_attribute(&plant->loc->sym, full_device);
  2257.             else
  2258.                 set_attribute(&plant->loc->sym, empty_device);
  2259.             }
  2260.         else
  2261.             {
  2262.             if(plant->current_output > USER_EPS * plant->max_state)
  2263.                 set_attribute(&plant->loc->sym, active_device);
  2264.             else
  2265.                 set_attribute(&plant->loc->sym, idle_device);
  2266.             }
  2267.     }
  2268.  
  2269. void set_mobile_icon(mobile *turtle)
  2270.     {
  2271.     if(turtle->loc->explored)
  2272.         {
  2273.         set_icon(&turtle->loc->sym, mobile_icon[turtle->class]);
  2274.         set_color(&turtle->loc->sym, mobile_color[turtle->class]);
  2275.         update_mobile_icon(turtle);
  2276.         }
  2277.     }
  2278.  
  2279. void update_mobile_icon(mobile *turtle)
  2280.     {
  2281.     if(turtle->loc->explored)
  2282.         {
  2283.         if(turtle->steps_to_breed)
  2284.             set_attribute(&turtle->loc->sym, gravid_mobile);
  2285.         else
  2286.             if(turtle->active)
  2287.                 set_attribute(&turtle->loc->sym, active_mobile);
  2288.             else
  2289.                 set_attribute(&turtle->loc->sym, idle_mobile);
  2290.         }
  2291.     }
  2292.  
  2293. void update_environment()
  2294.     {
  2295.     real base, solar_factor, temperature_factor, air_factor, water_factor, growth_factor;
  2296.  
  2297.     env.time++;
  2298.     base = 0.5 + BASE_RANGE * sin(OMEGA * env.time);
  2299.  
  2300.     solar_factor = base + random(2 * SOLAR_RANGE) - SOLAR_RANGE;
  2301.     temperature_factor = solar_factor + random(2 * TEMPERATURE_RANGE) - TEMPERATURE_RANGE;
  2302.  
  2303.     air_factor = temperature_factor + random(2 * AIR_RANGE) - AIR_RANGE;
  2304.     water_factor = temperature_factor + random(2 * WATER_RANGE) - WATER_RANGE;
  2305.     growth_factor = 1 - (temperature_factor + random(2 * GROWTH_RANGE) - GROWTH_RANGE);
  2306.  
  2307.     env.solar_factor = max(0, min(1, (env.solar_factor + solar_factor) / 2));
  2308.     env.temperature_factor = max(0, min(1, (env.temperature_factor + temperature_factor) / 2));
  2309.     env.air_factor = max(0, min(1, (env.air_factor + air_factor) / 2));
  2310.     env.water_factor = max(0, min(1, (env.water_factor + water_factor) / 2));
  2311.     env.growth_factor = max(0, min(1, (env.growth_factor + growth_factor) / 2));
  2312.     }
  2313.  
  2314. real calc_zeta(zeta_factor zeta_f, cell *loc)
  2315.     {
  2316.     switch(zeta_f)
  2317.         {
  2318.         case zeta_1:
  2319.         return 1;
  2320.         break;
  2321.  
  2322.         case zeta_solar:
  2323.         return env.solar_factor;
  2324.         break;
  2325.  
  2326.         case zeta_temperature:
  2327.         return env.temperature_factor;
  2328.         break;
  2329.  
  2330.         case zeta_water:
  2331.         return pow(env.water_factor * (1 - loc->ground_factor), 0.5);
  2332.         break;
  2333.  
  2334.         case zeta_air:
  2335.         return pow(env.air_factor * (1 - loc->ground_factor), 0.5);
  2336.         break;
  2337.  
  2338.         case zeta_growth:
  2339.         return pow(env.growth_factor * loc->ground_factor, 0.5);
  2340.         break;
  2341.  
  2342.         default:
  2343.         assert(0);
  2344.         break;
  2345.         }
  2346.     return 0;
  2347.     }
  2348.  
  2349. void start_game(cell *loc)
  2350.     {
  2351.     int k;
  2352.  
  2353.     install_device(habitat, loc);
  2354.     display_cell(loc);
  2355.     display_neighbors(loc);
  2356.  
  2357.     place_near(space_shuttle, loc);
  2358.     for(k = 0; k < INITIAL_PARASITES; k++)
  2359.         place_mobile(alien_parasite);
  2360.     for(k = 0; k < INITIAL_BREEDERS; k++)
  2361.         place_mobile(alien_breeder);
  2362.     /* Almeno una breeder ha vita uguale alla sua vita media */
  2363.     sys.turtle[sys.tot_turtles - 1]->time_to_remove = mobile_max_age[alien_breeder] / 2;
  2364.     for(k = 0; k < INITIAL_GIZMOS; k++)
  2365.         place_mobile(plasma_gizmo);
  2366.     for(k = 0; k < INITIAL_MOLES; k++)
  2367.         place_mobile(alien_mole);
  2368.  
  2369.     display_frame();
  2370.     display_message(title_message);
  2371.     }
  2372.  
  2373. void end_game()
  2374.     {
  2375.     int k;
  2376.  
  2377.     lock_interface();
  2378.     for(k = 0; k < MANY_YEARS && !receive_interrupt(); k++)
  2379.         {
  2380.         do
  2381.             next_day(FALSE);
  2382.         while(env.time % BASE_PERIOD);
  2383.  
  2384.         display_map();
  2385.         display_frame();
  2386.         }
  2387.     unlock_interface();
  2388.  
  2389.     display_message(end_of_game);
  2390.     }
  2391.  
  2392. cell *place_mobile(mobile_class class)
  2393.     {
  2394.     cell *loc;
  2395.  
  2396.     do
  2397.         loc = &env.map[(int)floor(random(MAP_ROWS))][(int)floor(random(MAP_COLS))];
  2398.     while(loc->plant || loc->alfa_duct || loc->turtle);
  2399.  
  2400.     install_mobile(class, loc);
  2401.     display_cell(loc);
  2402.  
  2403.     return loc;
  2404.     }
  2405.  
  2406. cell *place_near(mobile_class class, cell *loc)
  2407.     {
  2408.     direction dir;
  2409.     cell *near_loc;
  2410.  
  2411.     for(dir = 0; dir < DIRECTION_NUMBER; dir++)
  2412.         {
  2413.         near_loc = neighbor(loc, dir);
  2414.         if(!near_loc->plant && !near_loc->alfa_duct && !near_loc->turtle)
  2415.             {
  2416.             install_mobile(class, near_loc);
  2417.             display_cell(near_loc);
  2418.             return near_loc;
  2419.             }
  2420.         }
  2421.     return NULL;
  2422.     }
  2423.  
  2424. int place_around_providers(int num, mobile_class class, resource_type output_type)
  2425.     {
  2426.     device *plant;
  2427.     int to_place, p;
  2428.  
  2429.     p = 0;
  2430.     plant = NULL;
  2431.     to_place = num;
  2432.     while(to_place)
  2433.         {
  2434.         while(!plant && p < sys.tot_plants)
  2435.             {
  2436.             if(sys.plant[p]->output_type != output_type || sys.plant[p]->broken)
  2437.                 p++;
  2438.             else
  2439.                 plant = sys.plant[p];
  2440.             }
  2441.  
  2442.         if(!plant)
  2443.             break;
  2444.  
  2445.         if(place_near(class, plant->loc))
  2446.             to_place--;
  2447.         else
  2448.             {
  2449.             plant = NULL;
  2450.             p++;
  2451.             }
  2452.         }
  2453.  
  2454.     return (num - to_place);
  2455.     }
  2456.  
  2457. boolean has_around_plants(cell *loc)
  2458.     {
  2459.     direction dir;
  2460.     cell *near_loc;
  2461.  
  2462.     for(dir = 0; dir < DIRECTION_NUMBER; dir++)
  2463.         {
  2464.         near_loc = neighbor(loc, dir);
  2465.         if(near_loc->plant)
  2466.             return TRUE;
  2467.         }
  2468.     return FALSE;
  2469.     }
  2470.  
  2471. boolean has_around_providers(cell *loc, resource_type output_type)
  2472.     {
  2473.     direction dir;
  2474.     cell *near_loc;
  2475.  
  2476.     for(dir = 0; dir < DIRECTION_NUMBER; dir++)
  2477.         {
  2478.         near_loc = neighbor(loc, dir);
  2479.         if(near_loc->plant &&
  2480.             near_loc->plant->output_type == output_type && !near_loc->plant->broken)
  2481.             return TRUE;
  2482.         }
  2483.     return FALSE;
  2484.     }
  2485.  
  2486. void attack_mobile(mobile *attacker, mobile *defender)
  2487.     {
  2488.     if(csi[attacker->class][defender->class])
  2489.         {
  2490.         defender->eta = max(0, defender->eta - 1 / csi[attacker->class][defender->class]);
  2491.         if(!defender->eta)
  2492.             {
  2493.             defender->time_to_remove = 1;
  2494.             if(defender->class < PRIMARY_MC_NUMBER)
  2495.                 display_message(robot_terminated);
  2496.             else
  2497.                 {
  2498.                 switch(defender->class)
  2499.                     {
  2500.                     case pantropic_form:
  2501.                     display_message(pantropic_terminated);
  2502.                     break;
  2503.  
  2504.                     case mutant_form:
  2505.                     display_message(mutant_terminated);
  2506.                     break;
  2507.  
  2508.                     case alien_parasite:
  2509.                     case alien_breeder:
  2510.                     case plasma_gizmo:
  2511.                     case alien_mole:
  2512.                     display_message(alien_terminated);
  2513.                     break;
  2514.  
  2515.                     case space_shuttle:
  2516.                     break;
  2517.  
  2518.                     default:
  2519.                     assert(0);
  2520.                     break;
  2521.                     }
  2522.                 }
  2523.             }
  2524.         defender->steps_to_breed = 0;
  2525.         if(defender->loc->explored)
  2526.             set_attribute(&defender->loc->sym, hit_mobile);
  2527.         }
  2528.     }
  2529.  
  2530. void move_mobile(mobile *turtle, cell *loc)
  2531.     {
  2532.     cell *prev_loc;
  2533.  
  2534.     prev_loc = turtle->loc;
  2535.     turtle->loc = loc;
  2536.  
  2537.     prev_loc->turtle = NULL;
  2538.     clear_cell(prev_loc);
  2539.  
  2540.     loc->turtle = turtle;
  2541.     if(turtle->explore_cell)
  2542.         loc->explored = TRUE;
  2543.  
  2544.     set_mobile_icon(turtle);
  2545.  
  2546.     if(turtle->steps_to_breed)
  2547.         {
  2548.         turtle->steps_to_breed--;
  2549.         if(!turtle->steps_to_breed)
  2550.             breed_mobile(turtle, prev_loc);
  2551.         }
  2552.     }
  2553.  
  2554. cell *jump_obstacle(mobile *turtle)
  2555.     {
  2556.     cell *near_loc;
  2557.  
  2558.     near_loc = neighbor(neighbor(turtle->loc, turtle->heading), turtle->heading);
  2559.     if(!near_loc->plant && !near_loc->alfa_duct && !near_loc->turtle)
  2560.         {
  2561.         move_mobile(turtle, near_loc);
  2562.         return near_loc;
  2563.         }
  2564.     else
  2565.         return NULL;
  2566.     }
  2567.  
  2568. void mate_mobile(mobile *father, mobile *mother)
  2569.     {
  2570.     if(mother->can_breed && !mother->steps_to_breed && random(1) < env.growth_factor)
  2571.         {
  2572.         switch(mother->class)
  2573.             {
  2574.             case pantropic_form:
  2575.             mother->steps_to_breed = PANTROPIC_STEPS_TO_BREED;
  2576.             break;
  2577.  
  2578.             case alien_breeder:
  2579.             mother->steps_to_breed = ALIEN_STEPS_TO_BREED;
  2580.             break;
  2581.  
  2582.             default:
  2583.             assert(0);
  2584.             break;
  2585.             }
  2586.         }
  2587.     }
  2588.  
  2589. void breed_mobile(mobile *mother, cell *loc)
  2590.     {
  2591.     switch(mother->class)
  2592.         {
  2593.         case pantropic_form:
  2594.         install_mobile((random(1) < MUTATION_RATIO)?
  2595.                         mutant_form : pantropic_form, loc);
  2596.         break;
  2597.  
  2598.         case alien_breeder:
  2599.         install_mobile((random(1) < ALIEN_FORMS_RATIO)?
  2600.                         alien_breeder : alien_parasite, loc);
  2601.         break;
  2602.  
  2603.         case plasma_gizmo:
  2604.         install_mobile(plasma_gizmo, loc);
  2605.         break;
  2606.  
  2607.         default:
  2608.         assert(0);
  2609.         break;
  2610.         }
  2611.     }
  2612.  
  2613.